#http://community.arsia-mons.com/index.php?showtopic=654&hl=sounds+ripped
#http://www.wooji-juice.com/blog/iphone-openal-ima4-adpcm.html
from struct import unpack, pack
class Mutable:pass
music = {}
music['data'] = open( 'sound.bin', 'rb' ).read()
music['count'] = unpack( '<I', music['data'][:4] )[0]
music['size'] = unpack( '<I', music['data'][4:8] )[0]
remainder = len( music['data'] )
clip_number = 0
music['clips'] = []

while remainder > music['size']:
    clip = {}
    start = 8 + clip_number * 96 + 0
    end = 8 + clip_number * 96 + 4
    clip['present'] = unpack( '<I', music['data'][start:end] )[0]
    start = 8 + clip_number * 96 + 4
    end = 8 + clip_number * 96 + 20
    clip['name'] = unpack( '<ssssssssssssssss', music['data'][start:end] )
    start = 8 + clip_number * 96 + 20
    end = 8 + clip_number * 96 + 24
    clip['offset'] = unpack( '<I', music['data'][start:end] )[0]
    start = 8 + clip_number * 96 + 24
    end = 8 + clip_number * 96 + 28
    clip['length'] = unpack( '<I', music['data'][start:end] )[0]
    remainder = len( music['data'] ) - end
    clip_number += 1
    music['clips'].append( clip )


for clip in music['clips']:
    start = 8 + 96 * music['count'] + clip['offset']
    end = 8 + 96 * music['count'] + clip['offset'] + clip['length']
    clip['data'] = music['data'][start:end]



import ctypes
from ctypes.util import find_library

try: openal = ctypes.CDLL( find_library( 'openal' ) )
except: openal = ctypes.CDLL( find_library( 'OpenAL32' ) )

device = openal.alcOpenDevice( None )
openal.alcMakeContextCurrent( openal.alcCreateContext( device, None ) )
Buffer = ctypes.c_uint()
Source = ctypes.c_uint()
openal.alGenBuffers( 1, ctypes.pointer( Buffer ) )

data = [ord(x) for x in music['clips'][74]['data']]

index_table = [
  -1, -1, -1, -1, 2, 4, 6, 8,
  -1, -1, -1, -1, 2, 4, 6, 8
]

step_table = [
  7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 
  19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 
  50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 
  130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
  337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
  876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 
  2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
  5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 
  15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 
]

#x=65
#while len(data) % x:
    #x+=1
#print x
#print len(data) / float(x)
#print len(data)*128./34.

print openal.alIsExtensionPresent("AL_EXT_IMA4"), 'availability'

new_data = ''
print len(data)
length = 0
while length < len(music['clips'][74]['data'])-32:

    header = unpack('>H',music['clips'][74]['data'][length:length+2])[0]
    step_index = header & 0x7f
    predictor = header & ( 0x1ff << 7 )
    if step_index>=len(step_table):step_index=len(step_table)-1
    step = step_table[step_index]
    

    nibbles = 64
    for x in xrange(length+2,length+2+nibbles / 2):
        low_nibble = data[x] & 0xf
        signed_low_nibble = low_nibble if low_nibble < 8 else low_nibble - 16
        step_index += index_table[low_nibble]
        if step_index>=len(step_table):step_index=len(step_table)-1
        diff = (signed_low_nibble + 0.5) * step / 4
        predictor += diff
        if predictor >32767: predictor = 32767
        elif predictor < -32768: predictor = -32768
        step = step_table[step_index]
        new_data += pack( '>h', predictor )
        
        high_nibble = (data[x] &240)>>4
        signed_high_nibble = high_nibble if high_nibble < 8 else high_nibble - 16
        step_index += index_table[high_nibble]
        if step_index>=len(step_table):step_index=len(step_table)-1
        diff = (signed_high_nibble + 0.5) * step / 4
        predictor += diff
        if predictor >32767: predictor = 32767
        elif predictor < -32768: predictor = -32768
        step = step_table[step_index]
        new_data += pack( '>h', predictor )

    length += nibbles / 2 + 2
print len(new_data)
outmemory = ( ctypes.c_ubyte * len( new_data ) )(*[ord(x) for x in new_data])

openal.alBufferData(
    Buffer,
    4355,
    outmemory,
    len( new_data ),
    11025
)

errors = openal.alGetError()
if errors: print 'error:', errors

openal.alGenSources( 1, ctypes.pointer( Source ) )
openal.alSourcei( Source, 4105, Buffer )
openal.alSourcei( Source, 4103, True )

def play(): openal.alSourcePlay( Source )

def stop():
    openal.alDeleteSources( 1, ctypes.pointer( Source ) )
    openal.alDeleteBuffers( 1, ctypes.pointer( Buffer ) )
    openal.alcCloseDevice( device )

play()
while True:pass
